﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
namespace MDS
{
    public class TradeRulesConfig : ConfigBase
    {
        private List<StockTradeRuleSetting> _stockTradeRules = new List<StockTradeRuleSetting>();
        private List<FutureTradeRuleSetting> _futureTradeRules = new List<FutureTradeRuleSetting>();

        private List<StockRangeSetting> _stockRangeSettings = new List<StockRangeSetting>();
        const string ConfigFile = "Config/QuotConf.xml";

        public TradeRulesConfig()
        {
            string configFileFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFile);

            try
            {
                XDocument configDoc = XDocument.Load(configFileFullPath);
                loadStkIdRangeSettings(configDoc);
                loadStockTradeRules(configDoc);
            }
            catch { }
        }

        public StockTradeRule GetStockTradeRule(string stkId, IEnumerable<StockExchange> exchanges)
        {
            StockRangeSetting rangeSetting = getStkIdRangeSetting(stkId, exchanges);
            if (rangeSetting == null)
                return null;
            var setting= _stockTradeRules.FirstOrDefault(
                rule => rule.Exch==rangeSetting.Exchange
                    && rule.StkType==rangeSetting.StkType
                    && rule.TradeType==rangeSetting.TradeType);
            if (setting == null)
                return null;
            else
                return setting.TradeRule;
        }
        public FutureTradeRule GetFutureTradeRule(string stkId,
            IEnumerable<FutureExchange> exchanges)
        {
            throw new NotImplementedException();
        }
        public StockExchange GetStockExchange(string stkId, IEnumerable<StockExchange> exchanges)
        {
            StockRangeSetting setting = getStkIdRangeSetting(stkId, exchanges);
            if (setting != null)
            {
                return setting.Exchange;
            }
            else
            {
                return default(StockExchange);
            }
        }
        public TradeType GetStockTradeType(string stkId, IEnumerable<StockExchange> exchanges)
        {
            StockRangeSetting setting = getStkIdRangeSetting(stkId, exchanges);
            if (setting != null)
            {
                return setting.TradeType;
            }
            else
            {
                return default(TradeType);
            }
        }
        public StkType GetStkType(string stkId, IEnumerable<StockExchange> exchanges)
        {
            StockRangeSetting setting = getStkIdRangeSetting(stkId, exchanges);
            if (setting != null)
            {
                return setting.StkType;
            }
            else
            {
                return default(StkType);
            }

        }



        private void loadStkIdRangeSettings(XDocument configDoc)
        {
            var stockIdAreas = configDoc.Descendants("StockIdArea");
            foreach (var stockIdArea in stockIdAreas)
            {

                var exchIDAttr = stockIdArea.Attribute("ExchID");
                var stkTypeAttr = stockIdArea.Attribute("StkType");
                var tradeTypeAttr = stockIdArea.Attribute("TradeType");
                StockExchange exch;
                StkType stkType;
                TradeType tradeType;
                if (exchIDAttr != null
                    && stkTypeAttr != null
                    && tradeTypeAttr != null
                    && StockExchange.TryParse(exchIDAttr.Value, out exch)
                    && StkType.TryParse(stkTypeAttr.Value, out stkType)
                    && TradeType.TryParse(tradeTypeAttr.Value, out tradeType))
                {
                    var idAreas = stockIdArea.Descendants("IdArea");
                    List<StkIdRange> idRanges = new List<StkIdRange>();
                    foreach (var idArea in idAreas)
                    {
                        var beginIdAttr = idArea.Attribute("BeginId");
                        var endIdAttr = idArea.Attribute("EndId");
                        int beginId;
                        int endId;
                        if (beginIdAttr != null
                            && endIdAttr != null
                            && !string.IsNullOrEmpty(beginIdAttr.Value)
                            && !string.IsNullOrEmpty(endIdAttr.Value)
                            && int.TryParse(beginIdAttr.Value, out beginId)
                            && int.TryParse(endIdAttr.Value, out endId)
                            && beginId <= endId)
                        {
                            StkIdRange stkIdRange = new StkIdRange(beginId, endId);
                            idRanges.Add(stkIdRange);
                        }
                    }

                    if (idRanges.Count > 0)
                    {
                        StockRangeSetting rangeSetting = new StockRangeSetting(exch, stkType, tradeType, idRanges);
                        _stockRangeSettings.Add(rangeSetting);
                    }
                }
                else
                {

                }
            }
        }
        private void loadStockTradeRules(XDocument configDoc)
        {
            var tradeRules = configDoc.Descendants("TradeRule");
            foreach (var rule in tradeRules)
            {
                var exchIDAttr = rule.Attribute("ExchID");
                var stkTypeAttr = rule.Attribute("StkType");
                var tradeTypeAttr = rule.Attribute("TradeType");
                var futureProducIdAttr = rule.Attribute("F_productId");

                if (exchIDAttr != null
                    && stkTypeAttr != null
                    && tradeTypeAttr != null)
                {
                    StockExchange exch;
                    StkType stkType;
                    TradeType tradeType;
                    if (StockExchange.TryParse(exchIDAttr.Value, out exch)
                        && StkType.TryParse(stkTypeAttr.Value, out stkType)
                        && TradeType.TryParse(tradeTypeAttr.Value, out tradeType))
                    {
                        StockTradeRule tradeRule = parseStockTradeRule(rule);
                        StockTradeRuleSetting ruleSetting = new StockTradeRuleSetting(exch, stkType, tradeType, tradeRule);
                        this._stockTradeRules.Add(ruleSetting);
                    }
                }
                else if (exchIDAttr != null
                    && futureProducIdAttr != null)
                {
                    FutureExchange exch;
                    string futureProductId = futureProducIdAttr.Value;
                    if (FutureExchange.TryParse(exchIDAttr.Value, out exch)
                        && !string.IsNullOrEmpty(futureProductId))
                    {
                        FutureTradeRule tradeRule = parseFutureTradeRule(rule);
                        FutureTradeRuleSetting ruleSetting = new FutureTradeRuleSetting(exch, futureProductId, tradeRule);
                        this._futureTradeRules.Add(ruleSetting);
                    }
                }

            }
        }

        private StockTradeRule parseStockTradeRule(XElement ruleElement)
        {
            StockTradeRule tradeRule = new StockTradeRule();
            if (ruleElement.Element("BuyLowerLimit") != null)
            {
                tradeRule.BuyLowerLimit = int.Parse(ruleElement.Element("BuyLowerLimit").Value);
            }
            if (ruleElement.Element("SellLowerLimit") != null)
            {
                tradeRule.SellLowerLimit = int.Parse(ruleElement.Element("SellLowerLimit").Value);
            }
            if (ruleElement.Element("BuyHighLimit") != null)
            {
                tradeRule.BuyHighLimit = int.Parse(ruleElement.Element("BuyHighLimit").Value);
            }
            if (ruleElement.Element("SellHighLimit") != null)
            {
                tradeRule.SellHighLimit = int.Parse(ruleElement.Element("SellHighLimit").Value);
            }
            if (ruleElement.Element("StockParValue") != null)
            {
                tradeRule.StockParValue = double.Parse(ruleElement.Element("StockParValue").Value);
            }
            if (ruleElement.Element("OrderPriceUnit") != null)
            {
                tradeRule.OrderPriceUnit = double.Parse(ruleElement.Element("OrderPriceUnit").Value);
                tradeRule.Decimal = getDecimal(tradeRule.OrderPriceUnit);
            }
            if (ruleElement.Element("ConvertQty") != null)
            {
                tradeRule.ConvertQty = int.Parse(ruleElement.Element("ConvertQty").Value);
            }
            if (ruleElement.Element("StkDeliveryDays") != null)
            {
                tradeRule.StkDeliveryDays = int.Parse(ruleElement.Element("StkDeliveryDays").Value);
            }
            if (ruleElement.Element("TradeUnit") != null)
            {
                tradeRule.TradeUnit = int.Parse(ruleElement.Element("TradeUnit").Value);
            }
            return tradeRule;
        }
        private FutureTradeRule parseFutureTradeRule(XElement ruleElement)
        {
            FutureTradeRule tradeRule = new FutureTradeRule();
            if (ruleElement.Element("MaxLimitOrderQty") != null)
            {
                tradeRule.MaxLimitOrderQty = int.Parse(ruleElement.Element("MaxLimitOrderQty").Value);
            }
            if (ruleElement.Element("MinLimitOrderQty") != null)
            {
                tradeRule.MinLimitOrderQty = int.Parse(ruleElement.Element("MinLimitOrderQty").Value);
            }
            if (ruleElement.Element("MaxMarketOrderQty") != null)
            {
                tradeRule.MaxMarketOrderQty = int.Parse(ruleElement.Element("MaxMarketOrderQty").Value);
            }
            if (ruleElement.Element("MinMarketOrderQty") != null)
            {
                tradeRule.MinMarketOrderQty = int.Parse(ruleElement.Element("MinMarketOrderQty").Value);
            }
            if (ruleElement.Element("ContractTimes") != null)
            {
                tradeRule.ContractTimes = int.Parse(ruleElement.Element("ContractTimes").Value);
            }
            if (ruleElement.Element("OrderPriceUnit") != null)
            {
                tradeRule.OrderPriceUnit = double.Parse(ruleElement.Element("OrderPriceUnit").Value);
                tradeRule.Decimal = getDecimal(tradeRule.OrderPriceUnit);
            }


            return tradeRule;


        }

        private int getDecimal(double value)
        {
            string valueStr = value.ToString();
            int dotIndex = valueStr.IndexOf('.');
            if (dotIndex > 0)
            {
                return valueStr.Length - dotIndex - 1;
            }
            else
                return 0;
        }

        private StockRangeSetting getStkIdRangeSetting(string stkId, IEnumerable<StockExchange> exchanges)
        {
            return _stockRangeSettings.FirstOrDefault(
                setting => setting.IsMatch(stkId) && exchanges.Contains(setting.Exchange)
                );
        }
        private StockRangeSetting getStkIdRangeSetting(int stkId, IEnumerable<StockExchange> exchanges)
        {
            return _stockRangeSettings.FirstOrDefault(
                setting => setting.IsMatch(stkId) && exchanges.Contains(setting.Exchange)
                );
        }
    }
}
